/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id$
 */
package wx.xml.xalan.xalan.templates;

import wx.xml.xalan.xalan.res.XSLTErrorResources;
import wx.xml.xalan.xalan.transformer.TransformerImpl;
import wx.xml.xalan.xpath.VariableStack;
import wx.xml.xalan.xpath.XPathContext;
import wx.xml.xalan.xpath.objects.XObject;

/**
 * An instance of this class holds unto a variable until
 * it is executed.  It is used at this time for global
 * variables which must (we think) forward reference.
 */
public class XUnresolvedVariable extends XObject {
    static final      long serialVersionUID = -256779804767950188L;
    /**
     * The node context for execution.
     */
    transient private int  m_context;

    /**
     * The transformer context for execution.
     */
    transient private TransformerImpl m_transformer;

    /**
     * An index to the point in the variable stack where we should
     * begin variable searches for evaluation of expressions.
     * This is -1 if m_isTopLevel is false.
     **/
    transient private int m_varStackPos = -1;

    /**
     * An index into the variable stack where the variable context
     * ends, i.e. at the point we should terminate the search.
     **/
    transient private int m_varStackContext;

    /**
     * true if this variable or parameter is a global.
     *
     * @serial
     */
    private boolean m_isGlobal;

    /**
     * true if this variable or parameter is not currently being evaluated.
     */
    transient private boolean m_doneEval = true;

    /**
     * Create an XUnresolvedVariable, that may be executed at a later time.
     * This is primarily used so that forward referencing works with
     * global variables.  An XUnresolvedVariable is initially pushed
     * into the global variable stack, and then replaced with the real
     * thing when it is accessed.
     *
     * @param obj             Must be a non-null reference to an ElemVariable.
     * @param sourceNode      The node context for execution.
     * @param transformer     The transformer execution context.
     * @param varStackPos     An index to the point in the variable stack where we should
     *                        begin variable searches for evaluation of expressions.
     * @param varStackContext An index into the variable stack where the variable context
     *                        ends, i.e. at the point we should terminate the search.
     * @param isGlobal        true if this is a global variable.
     */
    public XUnresolvedVariable(ElemVariable obj, int sourceNode,
                               TransformerImpl transformer,
                               int varStackPos, int varStackContext,
                               boolean isGlobal) {
        super(obj);
        m_context = sourceNode;
        m_transformer = transformer;

        // For globals, this value will have to be updated once we
        // have determined how many global variables have been pushed.
        m_varStackPos = varStackPos;

        // For globals, this should zero.
        m_varStackContext = varStackContext;

        m_isGlobal = isGlobal;
    }

    /**
     * For support of literal objects in xpaths.
     *
     * @param xctxt The XPath execution context.
     * @return This object.
     * @throws javax.xml.transform.TransformerException
     */
    public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException {
        if (!m_doneEval) {
            this.m_transformer.getMsgMgr().error
                (xctxt.getSAXLocator(), XSLTErrorResources.ER_REFERENCING_ITSELF,
                    new Object[]{((ElemVariable) this.object()).getName().getLocalName()});
        }
        VariableStack vars = xctxt.getVarStack();

        // These three statements need to be combined into one operation.
        int currentFrame = vars.getStackFrame();
        //// vars.setStackFrame(m_varStackPos);


        ElemVariable velem = (ElemVariable) m_obj;
        try {
            m_doneEval = false;
            if (-1 != velem.m_frameSize)
                vars.link(velem.m_frameSize);
            XObject var = velem.getValue(m_transformer, m_context);
            m_doneEval = true;
            return var;
        } finally {
            // These two statements need to be combined into one operation.
            // vars.setStackFrame(currentFrame);

            if (-1 != velem.m_frameSize)
                vars.unlink(currentFrame);
        }
    }

    /**
     * Set an index to the point in the variable stack where we should
     * begin variable searches for evaluation of expressions.
     * This is -1 if m_isTopLevel is false.
     *
     * @param top A valid value that specifies where in the variable
     *            stack the search should begin.
     */
    public void setVarStackPos(int top) {
        m_varStackPos = top;
    }

    /**
     * Set an index into the variable stack where the variable context
     * ends, i.e. at the point we should terminate the search.
     *
     * @param bottom The point at which the search should terminate, normally
     *               zero for global variables.
     */
    public void setVarStackContext(int bottom) {
        m_varStackContext = bottom;
    }

    /**
     * Tell what kind of class this is.
     *
     * @return CLASS_UNRESOLVEDVARIABLE
     */
    public int getType() {
        return CLASS_UNRESOLVEDVARIABLE;
    }

    /**
     * Given a request type, return the equivalent string.
     * For diagnostic purposes.
     *
     * @return An informational string.
     */
    public String getTypeString() {
        return "XUnresolvedVariable (" + object().getClass().getName() + ")";
    }


}
